import {ReferenceCollection} from "./ReferenceCollection";
import {ReferencePoolInfo} from "./ReferencePoolInfo";
import {IReference} from "./IReference";

export  class ReferencePool  {
    private static readonly s_ReferenceCollections:Map<any,ReferenceCollection> = new Map<any, ReferenceCollection>();

    static get Count(){
        return this.s_ReferenceCollections.size;
    }
    static GetAllReferencePoolInfos():ReferencePoolInfo[]
    {
        let result:ReferencePoolInfo[] = [];
        this.s_ReferenceCollections.forEach(((value, key) => {
            let info:ReferencePoolInfo = new ReferencePoolInfo(key,value.unusedReferenceCount,value.usingReferenceCount,
                value.acquireReferenceCount,value.releaseReferenceCount,value.addReferenceCount,value.removeReferenceCount);
            result.push(info);

        }));
        return result;
    }

    static ClearAll():void{
        this.s_ReferenceCollections.forEach(((value) => {
            value.RemoveAll();
        }));
        this.s_ReferenceCollections.clear();
    }

    static Acquire<T extends IReference>(type:(new ()=>T)):T{
        return this.GetReferenceCollection(type).Acquire(type);
    }

    static GetReferenceCollection<T extends IReference >(type:(new ()=>T)):ReferenceCollection
    {
        if(type == null){
            throw new Error("ReferenceType is invalid.");
        }
        let referenceCollection:ReferenceCollection = this.s_ReferenceCollections.get(type);
        if(referenceCollection == null){
            referenceCollection = new ReferenceCollection(type);
            this.s_ReferenceCollections.set(type,referenceCollection);
        }
        return referenceCollection;
    }

    static Release(reference:IReference):void
    {
        if (reference == null)
        {
            throw new Error("Reference is invalid.");
        }
        // if(!cc.js.isChildClassOf(reference.constructor,cc.Class)){
        //     throw new Error("is not class");
        // }
        let anytype:any = reference;
        this.GetReferenceCollection(anytype.__proto__).Release(reference);
    }

    static Add<T extends  IReference>(type:(new()=>T),count:number):void{
        this.GetReferenceCollection(type).Add(type,count);
    }

    static Remove<T extends IReference>(type:(new()=>T),count:number):void{
        this.GetReferenceCollection(type).Remove(count);
    }

    static RemoveAll<T extends IReference>(type:(new()=>T)):void
    {
        this.GetReferenceCollection(type).RemoveAll();
    }


}